package com.wx.proxy.cglib.aop;

import com.wx.proxy.cglib.CglibTest;
import com.wx.proxy.cglib.aop.annotation.Pointcut;
import com.wx.proxy.cglib.aop.annotation.WxAspect;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 容器对象
 * @description:
 * @author: wangxun
 * @createDate: 2021/12/27
 * @version: 1.0
 */
public class MyContainer {
    static Map<Class<?>, Object> container = new HashMap<>();



    static Set<String> classNames = new HashSet<>();
    static HashMap<Class<?>, Class<?>> aspectMap = new HashMap<>();

    /** 根路径 */
    public static final String BASE_PACKAGE = "com.wx.proxy.cglib";
    /**
     * 后缀
     */
    public static final String CLASS_FILE_SUFFIX  = ".class";

    static MyContainer instance = new MyContainer();
    private MyContainer(){
        try {
            // init 初始化 扫描
            init();
            // 加载切面类
            loadAspect();
            // 被代理类
            loadProxy();

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }




    /**
     * 扫描
     */
    private void init() {
        // 前置路径
        String classPath = MyContainer.class.getResource("/").getPath();

        // 包路径
        String packagePath = BASE_PACKAGE.replace(".", File.separator);
        // 包路径下的根目录
        File packageFile = new File(classPath + packagePath);

        addClass(packageFile,classPath);



    }

    /**
     * 添加全部的类文件
     * @param packageFile
     */
    private void addClass(File packageFile,String classPath) {
        if(packageFile.isDirectory()){
            File[] files = packageFile.listFiles();

            for (File file : files) {
                if(file.isDirectory()){
                    addClass(file,classPath);
                }else {
                    String path = file.getPath();
                    String suffixName = path.replace(path.replace("/", "\\").replaceFirst("\\\\", ""), "")
                            .replace("\\", ".")
                            .replace(CLASS_FILE_SUFFIX, "").split(BASE_PACKAGE)[1];
                    classNames.add(BASE_PACKAGE+suffixName);
                }
            }
        }
    }


    private void loadAspect() throws ClassNotFoundException, NoSuchMethodException {
        for (String className : classNames) {
            Class<?> aClass = Class.forName(className);
            // 先看哪个是Aspect类
            WxAspect wxAspect = aClass.getAnnotation(WxAspect.class);
            if(wxAspect != null){
                // 存在Aspect
                Method pointcut = aClass.getMethod("pointcut");
                // 获取切点
                Pointcut pointcutAnnotation = pointcut.getAnnotation(Pointcut.class);
                String[] value = pointcutAnnotation.value();
                // 添加切面注解
                for (String s : value) {
                    // 将注解 和 切面类都放到aspectMap
                    aspectMap.put(Class.forName(s), aClass);
                }
            }
        }
    }

    /**\
     * 加载被代理类
     */
    private void loadProxy() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        for (String className : classNames) {
            Class<?> aClass = Class.forName(className);
            WxAspect wxAspect = aClass.getAnnotation(WxAspect.class);
            if(wxAspect == null){
                Method[] methods = aClass.getDeclaredMethods();
                for (Method method : methods) {
                    // 获取方法上所有的注解
                    Annotation[] annotations = method.getAnnotations();
                    for (Annotation annotation : annotations) {
                        Set<Class<?>> classes = aspectMap.keySet();
                        for (Class<?> aClass1 : classes) {
                            // 比较方法上注解是否与切面的注解相同
                            if(annotation.annotationType() == aClass1){
                                // 相同就为其生成代理
                                // Enhancer 增强剂
                                Enhancer enhancer = new Enhancer();
                                // 设置父类
                                enhancer.setSuperclass(aClass);
                                enhancer.setCallback((Callback) aspectMap.get(aClass1).newInstance());
                                // 将代理类存储起来
                                container.put(aClass,enhancer.create());
                            }
                        }
                    }
                }
            }
        }
    }



    static MyContainer getInstance(){
         return instance;
   }


    <T> T getProxy(Class<T> cls){
        Object proxy = container.get(cls);
        if(proxy == null){
            throw new RuntimeException("生成代理对象出错，此类型不在管理范围");
        }

        return (T) proxy;
    }

}
